﻿using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Web;
using System.Web.Caching;
using System.Text.RegularExpressions;
using System.Security.Cryptography;

// [a1|a2][url]H[?NvarnameVvarvalue...]Q[?NvarnameVvarvalue...]F[?NvarnameVvarvalue...]C[?NcustomnameVcustomvalue]D[?base64datahash]E[?encodings]

//CRML=cached resource meta-locator: [url]?[[querystring?NvarnameVvarvalue...]|[form?NvarnameVvarvalue...]]

namespace FlexiCache
{
    public class CachedResourceFinder
    {
        internal static List<string> ExplicitMetatags
        {
            get
            {
                if (HttpContext.Current != null)
                {
                    if (HttpContext.Current.Items.Contains("metatag"))
                        return (List<string>)HttpContext.Current.Items["metatag"];
                }
                return new List<string>();
            }
        }

        internal static void SetExplicitMetatag(string metatag)
        {
            if (HttpContext.Current != null)
            {
                if (HttpContext.Current.Items.Contains("metatag"))
                    ((List<string>)HttpContext.Current.Items["metatag"]).Add(metatag);
                else
                {
                    List<string> newlist = new List<string>();
                    newlist.Add(metatag);
                    HttpContext.Current.Items.Add("metatag", newlist);
                }
            }
        }

        public CachedResourceFinder()
        {
        }

        /// <summary>
        /// Method creates a collection of meta-tags that can be used to build a cached resource meta-locator.
        /// </summary>
        /// <param name="cacheKey"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public static string[] CreateMetaTagsCollection(string cacheKey, HttpContext context)
        {
            List<string> metatags = new List<string>();

            if (context != null)
            {
                if (context.Request != null)
                {
                    string tmpValue = string.Empty;
                    foreach (string param in context.Request.QueryString.AllKeys)
                    {
                        if (cacheKey.Contains(string.Format("N{0}V", param.ToLower())))
                        {
                            if (!string.IsNullOrEmpty(context.Request.QueryString[param]))
                            {
                                tmpValue = context.Request.QueryString[param];
                                metatags.Add(HandleParameterTag(param, tmpValue));
                            }
                        }
                    }
                    if (string.Compare(context.Request.RequestType, "POST", true) == 0)
                    {
                        foreach (string param in context.Request.Form.AllKeys)
                        {
                            if (cacheKey.Contains(string.Format("N{0}V", param.ToLower())))
                            {
                                if (!string.IsNullOrEmpty(context.Request.Form[param]))
                                {
                                    tmpValue = context.Request.Form[param];
                                    metatags.Add(HandleParameterTag(param, tmpValue));
                                }
                            }
                        }
                    }
                    List<string> expTags = ExplicitMetatags;
                    foreach (string tag in expTags)
                    {
                        if (!metatags.Contains(tag))
                            metatags.Add(tag);
                    }
                    metatags.Sort();
                    tmpValue = context.Request.Path.ToLower();
                    metatags.Insert(0, HandlePathTag(tmpValue));
                }
            }

            return metatags.ToArray();
        }

        internal static string HandlePathTag(string originalPath)
        {
            if (originalPath.Length > 250)
                originalPath = string.Format("{0}/{1}", HashValue(originalPath), originalPath.Substring(originalPath.Length - 200));
            return string.Format("path={0}", originalPath);
        }

        internal static string HandleParameterTag(string paramName, string originalParamValue)
        {
            if (originalParamValue.Length > 50)
                originalParamValue = HashValue(originalParamValue);
            return string.Format("{0}={1}", paramName.ToLower(), originalParamValue);
        }

        private static string HashValue(string value)
        {
            MD5CryptoServiceProvider cryptoServiceProvider = new MD5CryptoServiceProvider();
            byte[] bytes = Encoding.UTF8.GetBytes(value);
            StringBuilder builder = new StringBuilder(value.Length.ToString().PadLeft(8, '0'));

            bytes = cryptoServiceProvider.ComputeHash(bytes);

            foreach (byte b in bytes)
                builder.Append(b.ToString("x2").ToLower());

            return builder.ToString();
        }
    }
}



